﻿using System;
using System.Collections.Generic;
using System.Xml;
using System.Text;

namespace SharePointClient
{
    /// <summary>
    /// Column of Sharepoint-Lists
    /// </summary>
    public class Field:IDisposable,IEnumerable<XmlAttribute>
    {
        XmlNode xml;
        string value;

        /// <summary>
        /// Creates Field from XML-Data (List/Fields/Field)
        /// </summary>
        /// <param name="field">Fields-Element from List-Xml</param>
        public Field(XmlNode field)
        {
            xml = field;
            //System.Diagnostics.Debug.WriteLine("Field: \"" + Name + "\" is " + DataType.ToString());
        }
        /// <summary>
        /// This Function is only used to rebuild the "FieldInformation"-Structure (CopyWebService) within a field
        /// </summary>
        /// <param name="id">Guid of Field</param>
        /// <param name="internalName">Column-Name</param>
        /// <param name="dataType">Type of Value</param>
        /// <param name="value">Value as string</param>
        public Field(Guid id,string internalName,string dataType,string value)
        {
            XmlDocument xdoc=new XmlDocument();
            XmlNode field = xdoc.AppendChild(xdoc.CreateElement("Field"));
            XmlAttribute att=xdoc.CreateAttribute("ID");
            att.Value=id.ToString();
            field.Attributes.Append(att);

            att=xdoc.CreateAttribute("InternalName");
            att.Value=internalName;
            field.Attributes.Append(att);

            att=xdoc.CreateAttribute("Type");
            att.Value=dataType;
            field.Attributes.Append(att);

            att=xdoc.CreateAttribute("Value");
            att.Value=value;
            this.value=value;
            field.Attributes.Append(att);
            xml=field;
        }
        

            
        /// <summary>
        /// Value is not used jet - does nothing
        /// </summary>
        public string Value
        {
            get { return value; }
            set { this.value = value; }
        }
        /// <summary>
        /// Returns count of attributes in Field
        /// </summary>
        public int Count
        {
            get
            {
                return xml.Attributes.Count;
            }
        }
        /// <summary>
        /// You can get an Attribute by Position
        /// </summary>
        /// <param name="i">Position from Count</param>
        /// <returns>XmlAttribute of Field</returns>
        public XmlAttribute this[int i]
        {
            get
            {
                return xml.Attributes[i];
            }
        }
        /// <summary>
        /// You can get an Attribute by Name
        /// </summary>
        /// <param name="name">Name of Attribute (Column)</param>
        /// <returns>XmlAttribute of Field</returns>
        public XmlAttribute this[string name]
        {
            get
            {
                foreach (XmlAttribute a in xml.Attributes)
                    if (a.Name == name) return a;
                return null;
            }
        }
        /// <summary>
        /// Returns SharePoint-Field-Name with encoded special Characters
        /// </summary>
        public string Name
        {
            get
            {
                XmlAttribute a = this["Name"];
                if (a == null) return ""; else return a.Value;
            }
        }
        /// <summary>
        /// Better readable Sharepont-Field-Name (without encoded Characters)
        /// </summary>
        public string ColumnName
        {
            get { return Name.Replace("_x0020_", " "); }
        }
        /// <summary>
        /// Returns DisplayName of Field (eg. Caption)
        /// </summary>
        public string DisplayName
        {
            get
            {
                XmlAttribute a = this["DisplayName"];
                if (a == null) return ""; else return a.Value;
            }
        }
        /// <summary>
        /// Returns Column-Name of SQL-Table wich is used to store that data
        /// </summary>
        public string ColName
        {
            get
            {
                XmlAttribute a = this["ColName"];
                if (a == null) return ""; else return a.Value;
            }
        }
        /// <summary>
        /// Returns Unique-FieldID
        /// </summary>
        public Guid Guid
        {
            get
            {
                XmlAttribute a = this["ID"];
                if (a == null) return Guid.Empty; else return new Guid(a.Value);
            }
        }
        /// <summary>
        /// Returns full Field XML-Data
        /// </summary>
        public XmlNode XmlData { get { return xml; } }

        /// <summary>
        /// Returns Sharepoint-Type of this Column
        /// </summary>
        public string TypeName
        {
            get
            {
                XmlAttribute a = this["Type"];
                if (a == null) return ""; else return a.Value;
            }
        }
        /// <summary>
        /// Returns real .NET Datatype of this Column
        /// </summary>
        public Type DataType
        {
            get
            {
                string type="String";
                XmlAttribute t = this["Type"];
                Type dType=type.GetType();
                if (t !=null)
                {
                    if (t.Value == "Number") return Type.GetType("System.Double"); // System.Number exists but is not the same as wanted
                    
                    dType = Type.GetType("System."+t.Value);
                    if (dType==null)
                    {
                        switch (t.Value)
                        {
                            case "ContentTypeId":
                            case "Text":
                            case "User":
                            case "Note":
                            case "Computed": // Hmmm... soll der Programmierer sich selbst drum kümmern
                            case "Lookup":
                            case "File":
                            case "URL":
                            case "UserMulti":
                            
                                type="String";break;

                            case "Counter":
                            case "Integer":
                            case "Attachments":
                            
                                type = "Int32"; break;
                            case "ModStat": // Genehmigungsstatuskennung
                            case "Recurrence": //Serie
                            case "CrossProjectLink":
                            case "AllDayEvent":
                                type = "Boolean"; break;
                            
                                
                            default:
                                System.Diagnostics.Debugger.Break();
                                break;
                        }
                        dType=Type.GetType("System."+type);
                    }
                }
                return dType;
            }
        }
        /// <summary>
        /// Converts Data to Real .NET Datatype
        /// </summary>
        /// <param name="value">String-Encoded-Data</param>
        /// <returns>Data in .NET Type (e.g. DateTime)</returns>
        public object ConvertToType(string value)
        {
            object x;
            Type d = DataType;
            if (d.Name=="String" && value.IndexOf(";#")>=0) value=value.Substring(value.IndexOf(";#")+2);
            if (d.Name=="Double")
                value = value.Replace(".", System.Globalization.CultureInfo.CurrentCulture.NumberFormat.CurrencyDecimalSeparator);
            else if (d.Name=="Boolean")
                value=(value!="0").ToString();
            if (d.Name=="Guid") 
                x=new Guid(value);
            else
                x= Convert.ChangeType(value, d);
            if (x.GetType().Name == "DateTime")
            {
                DateTime dt=new DateTime(((DateTime)x).Ticks, DateTimeKind.Utc);
                x = dt.ToLocalTime();
            }
           
            return x;
        }
        /// <summary>
        /// Returns FieldInfomation-Structure of this Field (CopyWebService)
        /// </summary>
        public SPWebService.Copy.FieldInformation FieldInformation
        {
            get
            {
                SPWebService.Copy.FieldInformation info = new SPWebService.Copy.FieldInformation();
                info.DisplayName = DisplayName;
                info.Id = Guid; ;
                info.InternalName = this["InternalName"].Value;
                
 //               foreach (SharePointClient.SPWebService.Copy.FieldType tn in SharePointClient.SPWebService.Copy.FieldType)
 //                   if (tn.ToString() = TypeName) info.Type = tn;
                info.Value=Value;
                return info;
            }
        }

        #region IDisposable Member
        /// <summary>
        /// End of Column
        /// </summary>
        public void Dispose()
        {
            // Hmmm .. something to do?
        
        }

        #endregion

        #region IEnumerable<XmlAttribute> Member

        public IEnumerator<XmlAttribute> GetEnumerator()
        {
            return (IEnumerator<XmlAttribute>) xml.Attributes.GetEnumerator();
        }

        #endregion

        #region IEnumerable Member

        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return xml.Attributes.GetEnumerator();
        }

        #endregion
    }
}
